import * as vscode from 'vscode';
import * as fs from 'fs';
import { EditorInputEvent, EditorOutputEvent } from '../com/editor-struct';
export class SgsEditorProvider implements vscode.CustomTextEditorProvider {
  public static readonly viewType = 'myscript.sgs';
  public static instance: SgsEditorProvider | undefined
  public webView: vscode.WebviewPanel | undefined
  constructor(
    private readonly context: vscode.ExtensionContext
  ) { }
  public static register(context: vscode.ExtensionContext): vscode.Disposable {
    if (!SgsEditorProvider.instance) {
      SgsEditorProvider.instance = new SgsEditorProvider(context)
    }
    const providerRegistration = vscode.window.registerCustomEditorProvider(SgsEditorProvider.viewType, SgsEditorProvider.instance);
    return providerRegistration;
  }
  resolveCustomTextEditor(document: vscode.TextDocument, webviewPanel: vscode.WebviewPanel, _token: vscode.CancellationToken): Thenable<void> | void {
    this.webView = webviewPanel;
    this.webView.webview.options = {
      enableScripts: true,
    }
    this.webView.webview.html = this.getHtml(this.webView.webview);
    function updateWebview() {
      webviewPanel.webview.postMessage({
        type: EditorInputEvent.SET_CONTENT,
        data: {
          content: document.getText()
        },
      });
    }
    const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(e => {
      if (e.document.uri.toString() === document.uri.toString()) {
        updateWebview();
      }
    });

    // Make sure we get rid of the listener when our editor is closed. 
    this.webView.onDidDispose(() => {
      changeDocumentSubscription.dispose();
    });

    // Receive message from the webview.
    webviewPanel.webview.onDidReceiveMessage(e => {

      switch (e.type) {
        case EditorOutputEvent.ENV_INFO:
          this.envInfo(webviewPanel, document);
          break;
        case EditorOutputEvent.UPDATE_FILE:
          this.updateTextDocument(document, e.data);
          break;
        case EditorOutputEvent.EXECUTE_CODE:
          this.executeCode(e.data);
          break;
        case EditorOutputEvent.OPEN_FILE:
          this.openFile();
          break;
        case EditorOutputEvent.COMPILE_CODE:
          this.exportCode(e.data);
          break;
        case EditorOutputEvent.EDITOR_READY:
          this.readyHandler();
          break;
      }
    });

  }

  private envInfo(webviewPanel: vscode.WebviewPanel, document: vscode.TextDocument) {
    const baseUri = webviewPanel.webview.asWebviewUri(vscode.Uri.file(this.context.asAbsolutePath('vs-ext/editor')));
    this.postMessage(EditorOutputEvent.ENV_INFO, {
      path: baseUri.toString() + '/',
      content: document.getText(),
    });
  }

  private readyHandler(){
    console.log('editor ready')
    const tabs = vscode.window.tabGroups.all
    console.log(tabs)
    this.postMessage(EditorOutputEvent.EDITOR_READY,{});
  }

  private openFile() {
    vscode.window.showOpenDialog().then((res) => {
      if (!res || !res[0]) {
        this.postMessage(EditorOutputEvent.OPEN_FILE, {
          data: null,
        });
        return
      }
      const data = fs.readFileSync(res[0].fsPath).toString('utf-8')
      this.postMessage(EditorOutputEvent.OPEN_FILE, {
        data,
      });
    })
  }

  private exportCode(tokens: string) {
    vscode.window.showSaveDialog({
      title: 'export code',
      filters: {
        sgscript: ['json'],
        javascript: ['js'],
        python: ['py'],
      }
    }).then((res) => {
      if (!res) {
        this.postMessage(EditorOutputEvent.OPEN_FILE, {});
        return
      }
      fs.writeFileSync(res.fsPath, tokens);
      this.postMessage(EditorOutputEvent.OPEN_FILE, {
        data: res,
      });
    })
  }

  public postMessage(eventType: EditorOutputEvent | EditorInputEvent, data: any, isRes = true) {
    if (!this.webView) {
      console.error('webview not found')
      return
    }
    const res = isRes ? '-res' : ''
    this.webView.webview.postMessage({
      type: eventType + res,
      data
    });

  }
  private getHtml(webview: vscode.Webview) {
    const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'vs-ext/editor', 'style.css'));
    const scriptResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'vs-ext/editor', 'sg-script.umd.js'));
    return `
        <!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>sg-script</title>
    <link rel="stylesheet" href="${styleResetUri}" />
    <style>
      *{
        margin: 0;
        padding: 0;
      }
      .loading{
        width: 100%;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 32px;
        color: #fff;
        background-color: black;
      }
    </style>
  </head>
  <body>
    <div id="app" dropzone>
    <div class="loading">
        loading
      </div>
    </div>
    <script src="${scriptResetUri}"></script>
  </body>
</html>

        `
  }


  updateTextDocument(document: vscode.TextDocument, json: any) {
    const edit = new vscode.WorkspaceEdit();
    edit.replace(
      document.uri,
      new vscode.Range(0, 0, document.lineCount, 0),
      json);

    return vscode.workspace.applyEdit(edit);
  }

  private async executeCode(tokens: any) {
    const root = this.context.extensionUri;
    const tempPath = vscode.Uri.joinPath(root, 'data/temp.json')
    fs.writeFileSync(tempPath.fsPath, JSON.stringify(tokens));
    const shell = new vscode.ShellExecution(`./bin/sgs-vm ./data/temp.json`, { cwd: root.fsPath });
    const task = new vscode.Task(
      {
        type: 'shell',
        name: 'sgs',
      },
      vscode.TaskScope.Workspace,
      'sgs execute',
      'sgs',
      shell
    )
    vscode.tasks.executeTask(task);
    this.postMessage(EditorOutputEvent.EXECUTE_CODE, tokens);
  }
}